package com.jmxcfc.blfsc.ssq.service.reguser.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.jmxcfc.blfsc.common.common.enums.ProcessStateEnum;
import com.jmxcfc.blfsc.common.common.request.BaseRequest;
import com.jmxcfc.blfsc.common.common.response.BaseResponse;
import com.jmxcfc.blfsc.common.exception.AfterOutboundException;
import com.jmxcfc.blfsc.common.exception.BeforeOutboundException;
import com.jmxcfc.blfsc.common.exception.OutboundException;
import com.jmxcfc.blfsc.common.sign.SignRequest;
import com.jmxcfc.blfsc.common.sms.BaseContext;
import com.jmxcfc.blfsc.common.validation.rule.RequestFieldRule;
import com.jmxcfc.blfsc.common.validation.rule.SignRulesUtil;
import com.jmxcfc.blfsc.ssq.common.Constants;
import com.jmxcfc.blfsc.ssq.entity.QueryUserApplyCertSub;
import com.jmxcfc.blfsc.ssq.entity.RegUserPersonalSub;
import com.jmxcfc.blfsc.ssq.modle.response.SsqResponse;
import com.jmxcfc.blfsc.ssq.service.SignatureService;
import com.jmxcfc.blfsc.ssq.service.reguser.IQueryUserApplyCertRequestService;
import com.jmxcfc.blfsc.ssq.service.reguser.IQueryUserApplyCertSubService;
import com.jmxcfc.blfsc.ssq.service.reguser.IRegUserPersonalSubService;
import com.jmxcfc.blfsc.ssq.util.HttpUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import javax.annotation.PostConstruct;
import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * 功能描述
 * 异步用户申请状态查询实现类
 * 请求参数:account(账户,取值身份证号)、taskId任务Id,取值于:根据业务号requestNo查询SSQ_REG_USER_PERSONAL_SUB表(注册个人用户并申请证书接口)
 * @author: pbs
 * @date: 2024年09月03日 23:47
 */
@Service
@Slf4j
public class QueryUserApplyCertRequestServiceImpl implements IQueryUserApplyCertRequestService {

    //查询用户证书申请状态的请求地址
    @Value("${com.ssq.queryUserApplyCertUrl}")
    private String queryUserApplyCertUrl;

    private Map<String,ProcessStateEnum> statusMap;

    private IQueryUserApplyCertSubService queryUserApplyCertSubService;


    private IRegUserPersonalSubService regUserPersonalSubService;

    private SignatureService signatureService;


    private RestTemplate restTemplate;



    @Autowired
    public void setRegUserPersonalSubService(IRegUserPersonalSubService regUserPersonalSubService) {
        this.regUserPersonalSubService = regUserPersonalSubService;
    }

    @Autowired
    public void setSignatureService(SignatureService signatureService) {
        this.signatureService = signatureService;
    }

    @Autowired
    public void setQueryUserApplyCertSubService(IQueryUserApplyCertSubService queryUserApplyCertSubService) {
        this.queryUserApplyCertSubService = queryUserApplyCertSubService;
    }

    @Autowired
    public void setRestTemplate(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }


    /**
     * 初始化statusMap,key=status,判断场景如下
     1:新申请 2:申请中 =>置为处理中
     3:超时 4:申请失败
     5:成功 6:失败重试
     -1:无效的申请（系统异常） 0:taskId不存在或已过期
     注:1和2建议再次查询，其它状态需重新申请证书
     */
    @PostConstruct
    private void initStatusMap(){
        statusMap = new HashMap<>(8);
        statusMap.put("-1",ProcessStateEnum.FAILURE);
        statusMap.put("0",ProcessStateEnum.FAILURE);
        statusMap.put("1",ProcessStateEnum.PROCESSING);
        statusMap.put("2",ProcessStateEnum.PROCESSING);
        statusMap.put("3",ProcessStateEnum.FAILURE);
        statusMap.put("4",ProcessStateEnum.FAILURE);
        statusMap.put("5",ProcessStateEnum.SUCCESS);
        statusMap.put("6",ProcessStateEnum.FAILURE);
    }
    /**
     * 执行入口
     * 规则校验:业务号字段、用户账号account(证件号码)
     * @param requestMessage
     * @return
     */
    @Override
    public BaseResponse<QueryUserApplyCertSub> sendRequest(BaseRequest<SignRequest<JSONObject>> requestMessage) {
        BaseContext<String> baseContext = new BaseContext<>();
        //头部参数校验规则:业务号
        List<RequestFieldRule<?>> headerElementRules = baseContext.getHeaderElementRules();
        headerElementRules.add(SignRulesUtil.getRequestNoRule());
        //请求体参数校验:用户账号account(证件号码)
        List<RequestFieldRule<?>> bodyElementRules = baseContext.getBodyElementRules();
        bodyElementRules.add(SignRulesUtil.getIdCodeRule());
        return execute(requestMessage, baseContext);
    }

    /**
     * 参数组织
     * 1、account(账户,取值身份证号)、taskId任务Id,取值于:根据业务号requestNo查询SSQ_REG_USER_PERSONAL_SUB表,取最新一条(注册个人用户并申请证书接口)
     * 2、如果SSQ_REG_USER_PERSONAL_SUB查询到taskId为空,则抛出异常:
     throw new BeforeOutboundException("异步申请状态查询接口，接口参数组装：根据业务号查询taskId，查无 注册个人用户并申请证书接口的返回的taskId")
     * @param request
     * @param response
     * @param baseContext
     * @throws BeforeOutboundException
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void beforeOutbound(BaseRequest<SignRequest<JSONObject>> request,  BaseResponse<QueryUserApplyCertSub> response, BaseContext<String> baseContext) throws BeforeOutboundException {
        String requestNo = request.getHeader().getRequestNo();
        try {
            log.info("请求业务号requestNo:{},查询用户证书申请状态接口,前置处理:数据落库和参数组装", requestNo);

            QueryUserApplyCertSub queryUserApplyCertSub = new QueryUserApplyCertSub();
            queryUserApplyCertSub.setRequestNo(requestNo);

            //参数组织、queryUserApplyCertSub设置值
            String requestParamStr = buildParam(request, queryUserApplyCertSub);

            //由于是签名参数追加为url参数:/openapi/v2/ /user/async/applyCert/status?developerId=aaaaaa&rtick=14840209310001&signType=rsa
            String urlPathParams = signatureService.buildUrlPathParams(queryUserApplyCertUrl, "", requestParamStr);
            //请求路径的url的参数
            baseContext.setExtendStr(urlPathParams);
            //设置请求
            baseContext.setRestHttpEntity(HttpUtils.creatRequestEntity(requestParamStr));
            //保存数据
            queryUserApplyCertSubService.save(queryUserApplyCertSub);
            //主键
            baseContext.setRecordId(queryUserApplyCertSub.getId());
            log.info("请求业务号requestNo:{},查询用户证书申请状态接口,前置处理结束", requestNo);
        } catch (Exception e) {
            log.error("请求业务号requestNo:{},前置处理异常:{}", requestNo, e.getMessage(), e);
            throw new BeforeOutboundException(e.getMessage(), e);
        }
    }

    /**
     * 外呼请求
     * @param request
     * @param response
     * @param baseContext
     * @throws OutboundException
     */
    @Override
    public void outbound(BaseRequest<SignRequest<JSONObject>> request,  BaseResponse<QueryUserApplyCertSub> response, BaseContext<String> baseContext) throws OutboundException {
        try{
            //请求url的,必须要用URL,否则restTemplate会对url进行
            URI requestUrl = new URI( StringUtils.join(queryUserApplyCertUrl, baseContext.getExtendStr()));
            log.info("请求业务号requestNo:{},查询用户证书申请状态接口,发送请求外呼,请求地址:{},请参数:{}",request.getHeader().getRequestNo(),requestUrl,baseContext.getRestHttpEntity().getBody());
            String resp = restTemplate.postForObject(requestUrl, baseContext.getRestHttpEntity(), String.class);
            log.info("请求业务号requestNo:{},查询用户证书申请状态接口,发送请求外呼,响应内容:{}", request.getHeader().getRequestNo(), resp);
            baseContext.setRestResponse(resp);
        } catch (Exception e) {
            log.error("请求业务号requestNo:{},查询用户证书申请状态接口,发送请求外呼异常:{}", request.getHeader().getRequestNo(), e.getMessage());
            throw new OutboundException(e.getMessage(), e);
        }
    }


    /**
     * 1、状态判断:
      "errno": 0时取值status:
      1:新申请 2:申请中 =>置为处理中
      3:超时 4:申请失败
      5:成功 6:失败重试
     -1:无效的申请（系统异常） 0:taskId不存在或已过期
     注:1和2建议再次查询，其它状态需重新申请证书
     * @param request
     * @param response
     * @param baseContext
     * @throws AfterOutboundException
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void afterOutbound(BaseRequest<SignRequest<JSONObject>> request,  BaseResponse<QueryUserApplyCertSub> response, BaseContext<String> baseContext) throws AfterOutboundException {
        String requestNo = request.getHeader().getRequestNo();
        try{
            log.info("请求业务号requestNo:{},查询用户证书申请状态接口,后置处理:解析响应结果", requestNo);
            QueryUserApplyCertSub queryUserApplyCertSub = new QueryUserApplyCertSub();
            queryUserApplyCertSub.setRequestNo(requestNo);
            //注意这边是根据主键更新
            queryUserApplyCertSub.setId(baseContext.getRecordId());
            SsqResponse ssqResponse = JSON.parseObject(baseContext.getRestResponse(),SsqResponse.class);
            //错误码值,0:成功
            String errno = ssqResponse.getErrno();
            //错误信息描述
            String errmsg = ssqResponse.getErrmsg();
            log.info("请求业务号requestNo:{},查询用户证书申请状态接口,响应的结果 errno:{},errmsg:{}", requestNo, errno, errmsg);
            String status = "";
            if (StringUtils.equals(errno, Constants.ERRNO_0)) {
                JSONObject data = Optional.ofNullable(ssqResponse.getData()).orElseGet(JSONObject::new);
                status = data.getString(Constants.STATUS);
                String message  = data.getString(Constants.MESSAGE);

                errmsg = StringUtils.isBlank(errmsg) ? message : StringUtils.joinWith(Constants.AND, errmsg, message);

                log.info("请求业务号requestNo:{},查询用户证书申请状态接口,响应结果status:{},message:{}", requestNo, status, message);
                response.getHeader().setProcessState(Optional.ofNullable(statusMap.get(status)).orElseGet(() -> {
                    log.error("请求业务号requestNo:{},查询用户证书申请状态接口,响应结果status的值超出处理范围,状态置为失败", requestNo);
                    return ProcessStateEnum.FAILURE;
                }));
                queryUserApplyCertSub.setStatus(status);
                queryUserApplyCertSub.setMessage(message);
            }else {
                response.getHeader().setProcessState(ProcessStateEnum.FAILURE);
            }
            queryUserApplyCertSub.setErrno(errno);
            queryUserApplyCertSub.setErrmsg(errmsg);
            queryUserApplyCertSubService.updateById(queryUserApplyCertSub);


            response.getHeader().setResCode(StringUtils.joinWith(Constants.AND, errno, status));
            response.getHeader().setResMessage(errmsg);
            response.setBody(queryUserApplyCertSub);
            log.info("请求业务号requestNo:{},注册个人用户并申请证书接口,后置处理结束", requestNo);
        } catch (Exception e) {
            log.error("请求业务号requestNo:{},注册个人用户并申请证书接口,后置处理异常:{}", requestNo, e.getMessage(), e);
            throw new AfterOutboundException(e.getMessage(), e);
        }
    }


    /**
     * 参数组织
     * {
     *   "account": "",
     *   "taskId": "="
     * }
     * @param request
     * @param queryUserApplyCertSub
     * @return
     */
    private String buildParam(BaseRequest<SignRequest<JSONObject>> request, QueryUserApplyCertSub queryUserApplyCertSub) {
        String requestNo = request.getHeader().getRequestNo();
        JSONObject requestParam = new JSONObject();
        requestParam.put(Constants.ACCOUNT, request.getBody().getIdCode());
        LambdaQueryWrapper<RegUserPersonalSub> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RegUserPersonalSub::getRequestNo, requestNo)
                .orderByDesc(RegUserPersonalSub::getCreateTime);
        List<RegUserPersonalSub> regUserPersonalSubList = regUserPersonalSubService.list(queryWrapper);
        if (CollectionUtils.isNotEmpty(regUserPersonalSubList) && StringUtils.isNotBlank(regUserPersonalSubList.get(0).getTaskId())) {
            requestParam.put(Constants.TASK_ID, regUserPersonalSubList.get(0).getTaskId());
            log.info("根据请求业务号requestNo:{},查询表:SSQ_REG_USER_PERSONAL_SUB,注册个人用户并申请证书接口的返回的taskId:{}", requestNo, regUserPersonalSubList.get(0).getTaskId());
        }else {
            log.error("根据请求业务号requestNo:{},查询注册个人用户并申请证书接口的返回的taskId,查询无taskId数据",requestNo);
            throw new BeforeOutboundException("异步申请状态查询接口，接口参数组装：根据业务号查询taskId，查无 注册个人用户并申请证书接口的返回的taskId");
        }

        queryUserApplyCertSub.setAccount(requestParam.getString(Constants.ACCOUNT));
        queryUserApplyCertSub.setTaskId(requestParam.getString(Constants.TASK_ID));
        log.info("请求业务号requestNo:{},参数组织完成,参数:{}", requestNo, JSON.toJSONString(requestParam));
        return JSON.toJSONString(requestParam);
    }


}